#ifndef GSPLOT_H
#define GSPLOT_H

#include "qcustomplot.h"
#include "gsdata.h"

#include <QDesktopWidget>
#include <QPointF>
#include <QString>
#include <QObject>
#include <QFont>

#include <qwt_polar_plot.h>
#include <qwt_polar_curve.h>
#include <qwt_series_data.h>

#include <qwt3d_surfaceplot.h>
#include <qwt3d_function.h>
#include <qwt_symbol.h>
#include <qwt_polar_grid.h>
#include <qwt_text.h>


using namespace itpp;
using namespace Qwt3D;
//From Qt's predefined QColor objects
//red, darkRed, blue, darkBlue, green, darkGreen
//cyan, darkCyan, magenta, darkMagenta, yellow, darkYellow
//black, gray, darkGray, lightGray, white, transparent
const int GSPColorMap[18] = { 7, 13,  9, 15,  8, 14,
                             10, 16, 11, 17, 12, 18,
                              2,  5,  4,  6,  3, 19};
const int GSPLineStyleMap[6] = {};
const int GSPMarkStyleMapQcp[9] = {0, 4, 6, 7, 10, 9, 3, 2, 8};
const int GSPMarkStyleMapQwt[9] = {-1, 0, 1, 2, 4, 5, 8, 9, 12};

class GSPlotPara
{
    Q_ENUMS(LineStyle)
    Q_ENUMS(MarkStyle)
public:
    enum LineStyle { None, Line, StepLeft, StepRight,
                     StepCenter, Impulse};
    enum MarkStyle { NoSymbol, Circle, Rect, Diamond,
                    DTriangle, UTriangle,
                    Plus, XCross, Star};
    //Label
    QString title;
    QString xLabel;
    QString yLabel;
    QString zLabel;
    //axis
    bool gridOn;
    //Size
    int width;
    int height;
    bool lockRatio;
    int resolution;
    bool autoScale;
    //Number of Curves
    int curveNums;
    //Data length
    int dataLength;
    //Legend
    bool legendEnable;
    QStringList legendTitle;//Item title
    //Line
    QList<double> lineWidth;
    QList<LineStyle> lineStyle;
    QList<QColor> lineColor;
    //Mark
    QList<MarkStyle> markStyle;
    QList<int> markSize;
    QList<QColor> markColor;
    //Font
    QFont fontStyle;
    QColor fontColor;
    //Show Points
    int maxShowPoints;
    bool showDataChanged;
    //delete enable
    bool deleteEnable;
    //clear enable
    bool clearEnable;
};

class GSPlot
{
    Q_ENUMS(PlotType)
public:
    enum PlotType { V1D, V2D, VPOLAR, V3D }; // Plot Function
    GSPlot();
    GSPlot(QString plotName, PlotType type, GSData dataX,
           int width, int height, int resolution);
    GSPlot(QString plotName, PlotType type,
           GSData dataX, GSData dataY,
           int width, int height, int resolution);
    GSPlot(QString plotName, PlotType type, GSData dataX,
           GSData dataY, GSData dataZ,
           int width, int height, int resolution);
    ~GSPlot();
    void initParameters(QString name,
                        int width, int height,
                        int resolution);
    void plotXY(mat x, mat y);
    void plotPolarXY(mat x, mat y);
    void plotXYZ(mat x, mat y, mat z);
    void plotUpdate();    
    void parameterSet(GSPlotPara para);
    void prepareData();

public:
    PlotType plotType; // Select Plot Type

    //General Plot Parameters
    GSPlotPara parameters;
    //Plot Functions, 2D, Polar, 3D ?
    QCustomPlot* plot2d = NULL;
    SurfacePlot* plot3d = NULL;
    QwtPolarPlot* plotPolar= NULL;
    GSData X;
    GSData Y;
    GSData Z;
private:
    mat mx;
    mat my;
    mat mz;
};

//Polar Plot Related Class
class PolarData: public QwtSeriesData<QwtPointPolar>
{
public:
    PolarData( vec xVec, vec yVec, size_t size ):
        xData(xVec), yData(yVec),
        d_size( size ){}

    virtual size_t size()const {return d_size;}

protected:
    vec xData;
    vec yData;
    size_t d_size;
};

class MyPolarData: public PolarData
{
public:
    MyPolarData(vec xVec, vec yVec, size_t size ):
        PolarData(xVec, yVec, size ){}

    virtual QwtPointPolar sample( size_t i ) const;

    virtual QRectF boundingRect() const
    {
        if ( d_boundingRect.width() < 0.0 )
            d_boundingRect = qwtBoundingRect( *this );

        return d_boundingRect;
    }
};
#endif // GSPLOT_H
